package tech

import "ssp/set"

func (s *Solve) SimpleColoring(g *Grid) (used bool, results []*Result) {
	tags := new([9][9][9]int)
	g.initTags(tags)
	color := 2
	strongLink := g.findStrongLinks()

	// Optimized loop structure:
	// 1. Cache cell reference to avoid repeated grid lookups
	// 2. Iterate only over actual candidates instead of all 9 possible
	for rowNum := range 9 {
		for colNum := range 9 {
			cell := g.rows[rowNum].cells[colNum] // Cache cell reference
			if cell.solved() {
				continue
			}
			// Iterate only over candidates that exist in the cell (instead of 0-8)
			for _, cand := range cell.cands.GetList() {
				if tags[rowNum][colNum][cand] == 1 {
					tags[rowNum][colNum][cand] = color
					g.colorFlag(cell, cand, color, strongLink, tags) // Use cached cell
					color += 2
				}
			}
		}
	}

	ruleFuns := []func(*[9][9][9]int) (bool, []*Result){
		//g.colorRule2,
		g.colorRule4,
	}
	for _, f := range ruleFuns {
		if ok, rs := f(tags); ok {
			used = true
			results = append(results, rs...)
		}
	}
	return
}

func (g *Grid) colorFlag(start *Cell, cand int, color int, stronglinks map[[3]int][]*Cell, tags *[9][9][9]int) {
	anotherColor := color + 1 - color%2*2
	cells := stronglinks[[3]int{start.rowNum, start.colNum, cand}]
	for _, cell := range cells {
		if tags[cell.rowNum][cell.colNum][cand] == 1 {
			tags[cell.rowNum][cell.colNum][cand] = anotherColor
			g.colorFlag(cell, cand, anotherColor, stronglinks, tags)
		}
	}
}

func findStrongLinksInHouse(house *House, strongLinks map[[3]int][]*Cell) {
	candCells := make([][]*Cell, 9)
	for _, cell := range house.cells {
		if cell.solved() {
			continue
		}
		for _, cand := range cell.cands.GetList() {
			candCells[cand] = append(candCells[cand], cell)
		}
	}
	for cand, cells := range candCells {
		if len(cells) == 2 {
			strongLinks[[3]int{cells[0].rowNum, cells[0].colNum, cand}] = append(strongLinks[[3]int{cells[0].rowNum, cells[0].colNum, cand}], cells[1])
			strongLinks[[3]int{cells[1].rowNum, cells[1].colNum, cand}] = append(strongLinks[[3]int{cells[1].rowNum, cells[1].colNum, cand}], cells[0])
		}
	}
}

func (g *Grid) findStrongLinks() map[[3]int][]*Cell {
	links := make(map[[3]int][]*Cell)
	for _, house := range g.houses {
		findStrongLinksInHouse(house, links)
	}
	return links
}

func (g *Grid) colorRule2(tags *[9][9][9]int) (used bool, results []*Result) {
	for _, house := range g.houses {
		if ok, rs := g.colorRule2House(tags, house); ok {
			used = true
			results = append(results, rs...)
		}
	}
	return
}

func (g *Grid) colorRule2House(tags *[9][9][9]int, house *House) (used bool, results []*Result) {
	colorCandCells := map[[2]int][]*Cell{}
	for _, cell := range house.cells {
		for _, cand := range cell.cands.GetList() {
			colorCandCells[[2]int{tags[cell.rowNum][cell.colNum][cand], cand}] = append(
				colorCandCells[[2]int{tags[cell.rowNum][cell.colNum][cand], cand}], cell)
		}
	}
	for colorCand, cells := range colorCandCells {
		if len(cells) > 1 {
			color := colorCand[0]
			//cand := colorCand[1]
			//fmt.Println(color, cand, cells)
			result := new(Result)
			g.canRemovedMedusa(color, tags, result)
			result.addHelpCells(cells)
			result.setStrategyName("Simple Coloring Rule 2")
			results = append(results, result)
			used = true
		}
	}
	return
}
func (g *Grid) colorRule4(tags *[9][9][9]int) (used bool, results []*Result) {
	colorCandCells := map[[2]int][]*Cell{}
	for rowNum := range 9 {
		for colNum := range 9 {
			if g.rows[rowNum].cells[colNum].solved() {
				continue
			}
			for _, cand := range g.rows[rowNum].cells[colNum].cands.GetList() {
				color := tags[rowNum][colNum][cand] / 2 * 2
				key := [2]int{color, cand}
				colorCandCells[key] = append(colorCandCells[key], g.rows[rowNum].cells[colNum])
			}
		}
	}

	for colorCand, cells := range colorCandCells {
		//color := colorCand[0]
		cand := colorCand[1]
		for _, pair := range combine(cells, 2) {
			//if isSameHouse(pair) {
			//	continue
			//}
			color1 := tags[pair[0].rowNum][pair[0].colNum][cand]
			color2 := tags[pair[1].rowNum][pair[1].colNum][cand]
			if color1 == color2 {
				continue
			}
			if ok, rmCells := g.canRemoveSeenCands(set.NewSet(cand), pair); ok {
				//fmt.Println(color1, color2, cand, pair)
				result := new(Result)
				result.addRemoved(set.NewSet(cand), rmCells)
				g.addHelpCandsMedusa(color1, color2, tags, result)
				result.addHelpCells(pair)
				result.setStrategyName("Simple Coloring Rule 4")
				results = append(results, result)
				used = true
			}
		}
	}

	return
}
